#include "FunTrace.h"
#include <e32base.h>
#include "http.h"
#include "googlepositioning.h"
#include <aknglobalnote.h>
#include "Binder.h"
#include "HTTPUtils.h"


const TInt kGoogleTimeout = 15*1000000;

static void PrintNoteL(TRefByValue<const TDesC> aFormat, ...)
    {
    VA_LIST list;
    VA_START(list, aFormat);
    TBuf<256> buf;
    buf.FormatList(aFormat, list);
    VA_END(list);
	CAknGlobalNote* globalNote = CAknGlobalNote::NewLC();
	globalNote->ShowNoteL(EAknGlobalInformationNote, buf); 
    CleanupStack::PopAndDestroy(globalNote);
    }


CGooglePositionRequest::CGooglePositionRequest()
: CActive(EPriorityStandard),
iNwInfoPckg(iNwInfo)
{
CActiveScheduler::Add(this);
}

CGooglePositionRequest* CGooglePositionRequest::NewL()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CGooglePositionRequest* ret = NewLC();
	CleanupStack::Pop(ret);
	return ret;	
	}

CGooglePositionRequest* CGooglePositionRequest::NewLC()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CGooglePositionRequest* ret = new (ELeave) CGooglePositionRequest();
	CleanupStack::PushL(ret);
	ret->ConstructL();
	return ret;
	}

void CGooglePositionRequest::Cancel()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	CActive::Cancel();
	iTimeoutTimerTarget->Cancel();
	if(iTransaction != RHTTPTransaction())
		{
		iTransaction.Cancel();
	    iTransaction.Close();
	    iTransaction = RHTTPTransaction();
		}
	}


void CGooglePositionRequest::DoCancel()
{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	iTelephony->CancelAsync(CTelephony::EGetCurrentNetworkInfoCancel);
}

CGooglePositionRequest::~CGooglePositionRequest()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	Cancel();
	delete iTelephony;
	iTransaction.Close();
	iBody.Close();
	delete iPostData;
	iSession.Close();
	}

void CGooglePositionRequest::ConstructL()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	iTelephony = CTelephony::NewL();
	iPostData = NULL;
	iBody.CreateL(4096);
	iTimeoutTimer->CreateLocal();
	iTimeoutTimerTarget = new (ELeave) scalp::CActiveTarget(
			scalp::MakeFunctionL( scalp::Bind(&RTimer::Cancel, &iTimeoutTimer.Get())) );
	iTimeoutTimerTarget->AppendRunL( scalp::MakeFunctionL( scalp::Bind(&CGooglePositionRequest::TransactionTimeoutCallbackL, this) ) );
	}

static void Shift(TDes8& data, int startIndex, int leftOperand)
{
    int rightOperand = 24;

    for (int i = 0; i < 4; i++, rightOperand -= 8)
    {
        data[startIndex++] = (TChar)((leftOperand >> rightOperand) & 255);
    }
}

static int GetCode(TDesC8& data, int startIndex)
{
    return ((((int)data[startIndex] << 24) |
        ((int)data[startIndex+1] << 16) |
        ((int)data[startIndex+2] << 8) |
        ((int)data[startIndex+3])));
}

static TInt ToInt(const TDesC& des)
	{
	TLex lex(des);
	TInt ret;
	lex.Val(ret);
	return ret;
	}

static HBufC8* googlePostDataL(int cellTowerId, int mobileCountryCode, int mobileNetworkCode, int locationAreaCode)
	{
	TBuf8<55> data(55);
	data.Fill(0);
	data[1] = 14;     //0x0e;
	data[16] = 27;    //0x1b;
	data[47] = 255;   //0xff;
	data[48] = 255;   //0xff;
	data[49] = 255;   //0xff;
	data[50] = 255;   //0xff;
	data[28] = (cellTowerId > 65536) ? 5 : 3; 
    Shift(data, 17, mobileNetworkCode);
    Shift(data, 21, mobileCountryCode);
    Shift(data, 31, cellTowerId);
    Shift(data, 35, locationAreaCode);
    Shift(data, 39, mobileNetworkCode);
    Shift(data, 43, mobileCountryCode);	
	return data.AllocL();
	}


void CGooglePositionRequest::SubmitL(MGooglePositionRequestCallback* aTarget)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	__ASSERT_ALWAYS(!IsActive(), User::Leave(KErrInUse));
	iTarget = aTarget;
	iTelephony->GetCurrentNetworkInfo(iStatus, iNwInfoPckg);
	SetActive();
	}

void CGooglePositionRequest::SetConnectionInfoL(const RConnection& aConnection, const RSocketServ& aSocketServ)
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	iSession.OpenL();
	RStringPool strP = iSession.StringPool();
	RHTTPConnectionInfo connInfo = iSession.ConnectionInfo();
	connInfo.SetPropertyL ( strP.StringF(HTTP::EHttpSocketServ, RHTTPSession::GetTable() ), THTTPHdrVal (aSocketServ.Handle()) );
	TInt connPtr = REINTERPRET_CAST(TInt, &aConnection);
	connInfo.SetPropertyL ( strP.StringF(HTTP::EHttpSocketConnection, RHTTPSession::GetTable() ), THTTPHdrVal (connPtr) );
	}

void CGooglePositionRequest::CloseConnectionL()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	Cancel();
	iSession.Close();
	}

void CGooglePositionRequest::RunL()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	User::LeaveIfError(iStatus.Int());
	_LIT8(kUriStr, "http://www.google.com/glm/mmap");
	TUriParser8 uri;
	uri.Parse( kUriStr );
	RStringF method = iSession.StringPool().StringF(HTTP::EPOST,RHTTPSession::GetTable());
	CleanupClosePushL(method);
	iBody.Zero();
	delete iPostData;
	iPostData = NULL;
	iLastError = KErrNone;
	if(iTransaction != RHTTPTransaction())
		{
		iTransaction.Cancel();
		iTransaction.Close();
		}
	iTransaction = iSession.OpenTransactionL(uri, *this, method);
	_LIT8(kContentType, "application/binary");
	RHTTPRequestSetHeaderL(iSession, iTransaction.Request(), HTTP::EContentType, kContentType);
	iTransaction.Request().SetBody(*this);
	iLastError = KErrNone;
	iTransaction.SubmitL();
	iTimeoutTimerTarget->Cancel();
	iTimeoutTimer->After(iTimeoutTimerTarget->iStatus, kGoogleTimeout);
	iTimeoutTimerTarget->SetActive();
	CleanupStack::PopAndDestroy(&method);
	}

void CGooglePositionRequest::TransactionTimeoutCallbackL()
	{
	TFunTrace funTrace(__PRETTY_FUNCTION__);
	Cancel();
	SubmitL(iTarget);
	}


TBool CGooglePositionRequest::GetNextDataPart(TPtrC8& aDataPart)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	if(!iPostData)
		{
#ifdef __WINS__ 
	iPostData = googlePostDataL(958506, 525, 03, 92);
#else
	iPostData = googlePostDataL(iNwInfo.iCellId, ToInt(iNwInfo.iCountryCode), ToInt(iNwInfo.iNetworkId), iNwInfo.iLocationAreaCode);
#endif
		}
	aDataPart.Set( *iPostData );
	return ETrue;
	}

void CGooglePositionRequest::ReleaseData()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	delete iPostData;
	iPostData = NULL;
	}

TInt CGooglePositionRequest::OverallDataSize()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
	return KErrNotFound;
	}

TInt CGooglePositionRequest::Reset()
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
		return KErrNotSupported;
	}

TInt CGooglePositionRequest::RunError(TInt aError)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
iTarget->MGooglePositionRequestCallbackRunL( THTTPEvent::EFailed, aError, TCoordinate(), 0 );	    	  
	return KErrNone;
	}

void CGooglePositionRequest::MHFRunL(RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
if(aEvent.iStatus < KErrNone) iLastError = aEvent.iStatus;
	  switch (aEvent.iStatus)
	    {
			case THTTPEvent::EUnrecoverableError:
				iLastError = KErrNotReady; // for Symbian 5th ed + 
			  break;
	    case THTTPEvent::EGotResponseHeaders:
	      break;

	    case THTTPEvent::EGotResponseBodyData:
	    	{
		      MHTTPDataSupplier* body = aTransaction.Response().Body();
		      TPtrC8 part;
		      body->GetNextDataPart(part);
	    	  iBody.Append(part);
		      body->ReleaseData();
	    	}		      
	      break;

	    case THTTPEvent::ESucceeded:
	    case THTTPEvent::EFailed:
	      iTimeoutTimerTarget->Cancel();
	      iStatusCode = aTransaction.Response().StatusCode();
	      iTransaction = RHTTPTransaction();

	      TInt status = aEvent.iStatus;
	      TReal32 latitude, longitude, accuracy;
	      if(aEvent.iStatus == THTTPEvent::ESucceeded)
			{
				if(iBody.Length() >= 15 + 4)
					{
					int result = GetCode(iBody, 3);
					latitude = (double)GetCode(iBody, 7) / 1000000;
					longitude = (double)GetCode(iBody, 11) / 1000000;
					accuracy = GetCode(iBody, 15);
					}
				else
					{
					status = THTTPEvent::EFailed;
					}
			}
			iTarget->MGooglePositionRequestCallbackRunL( status, iLastError, TCoordinate(latitude, longitude), accuracy );	    	  
		      aTransaction.Cancel();
		      aTransaction.Close();
			
	      break;
	      
	    case THTTPEvent::ERedirectedPermanently:
	      break;
	    	
	    case THTTPEvent::ERedirectedTemporarily:
	      break;
	    	
	    default:
	      break;
	    }
	}
TInt CGooglePositionRequest::MHFRunError(TInt aError, RHTTPTransaction aTransaction, const THTTPEvent& aEvent)
	{
TFunTrace funTrace(__PRETTY_FUNCTION__);
return KErrNone;
	}

